#
#  <Test>
#    <TestType>DRT</TestType>
#    <Summary>Verifies the New-PsSpecProject cmdlet</Summary>
#  </Test>
##
## Test case goals:
##
## - Simple project can be added / removed (name, creator) (New-PsSpecProject)
## - Does not accept invalid characters for project name
## - Does not accept empty project name
## - Does not accept too long project name
## - No error when creating a project with SQL-injection characters
## - Can add new owner to project (Add-ProjectOwner / Remove-ProjectOwner)
## - Can remove an owner from project 
## - Other owner can add new owner (Add-SpecAuthor / Remove-SpecAuthor)
## - Can add spec author
## - Can remove a spec author
## - Spec author cannot add new owner
## - Random user has read access to project
## - Owner can hide project and cmdlets from a user (Remove-ProjectReader)
## - Owner can hide project and cmdlets from a security group
## - Owner can unhide project from user (Add-ProjectReader)
## - Owner can unhide project from security group
## - Spec author cannot hide projectl 
##
. (join-path $args[0] "..\Asserts.ps1")

Add-PsSnapin PsSpecCmdletManagement -ErrorAction SilentlyContinue
$testService = "http://localhost/cmdletdesigner/cmdlet.asmx"
$testDatabase = "AspenManagement"
$testDatasource = ".\SQLEXPRESS"
$sqlCommand = Resolve-Path (Join-Path $args[0] "Scripts\Invoke-SqlCommand.ps1")

## Function to clear spec history
function ClearSpecHistory
{
    $clearSpecHistorySql = "DELETE FROM SpecHistory"
    [void] (& $sqlCommand $testDataSource $testDatabase $clearSpecHistorySql)
}

$error.Clear()

## Remove old test data
Get-PsSpecProject "TestProject*" -Service $testService | Remove-PsSpecProject -Service $testService -Force

## Test noun equality
$noun = New-Object Microsoft.PowerShell.CmdletManagement.PsSpecNoun
$noun.Name = "Test"
$noun.Definition = "TestDef"
$noun.ProjectName = "TestProject"

$noun2 = New-Object Microsoft.PowerShell.CmdletManagement.PsSpecNoun
$noun2.Definition = "TestDef"
$noun2.Name = "Test"
$noun2.Id = 101

Assert (-not $noun.Equals($noun2)) "Nouns should not be equal, project names are different"

$noun2.ProjectName = "TestProject"
Assert $noun.Equals($noun2) "Nouns should be equal, project names are fixed"

$noun2.Definition = "Foo"
Assert (-not $noun.Equals($noun2)) "Nouns should not be equal, definitions are different"
$error.Clear()

## Check Get-Project with no project, wildcards, and no error
$projects = @(Get-PsSpecProject -Service $testService)
AssertEquals 0 $error.Count "Should be able to get all projects"
$error.Clear()

## Check Get-Project with missing project, no wildcards, and error
Get-PsSpecProject "23afasdflkasjdflskajfdsf" -Service $testService -ErrorAction SilentlyContinue
AssertEquals 1 $error.Count "Should have generated an error for no-globbing project name"
$error.Clear()

## Simple add project
$projectReturned = New-PsSpecProject "TestProject" "This is a description of my project" -Service $testService

## Test the returned object
AssertEquals "TestProject" $projectReturned.Name
AssertEquals "This is a description of my project" $projectReturned.Description
AssertEquals "$env:userdomain\$env:username" $projectReturned.Owner
AssertEquals "Microsoft.PowerShell.CmdletManagement.PsSpecProject" $projectReturned.GetType().FullName

## See that the add was successful
$projects = @(Get-PsSpecProject "TestProject" -Service $testService)
AssertEquals 1 $projects.Count "Should have created project"
$project = $projects[0]
AssertEquals "TestProject" $project.Name
AssertEquals "This is a description of my project" $project.Description
AssertEquals "$env:userdomain\$env:username" $project.Owner
Assert ($project.Id -gt 0) "Projects should have an ID"

## Add project with null description
$projectReturned = New-PsSpecProject "TestProject2" $null -Service $testService

## Test the returned object
AssertEquals "TestProject2" $projectReturned.Name
AssertEquals $null $projectReturned.Description
AssertEquals "$env:userdomain\$env:username" $projectReturned.Owner
AssertEquals "Microsoft.PowerShell.CmdletManagement.PsSpecProject" $projectReturned.GetType().FullName

ClearSpecHistory

Remove-PsSpecProject "TestProject2" -Service $testService -Force

## Verify that the history was updated
$history = @($projectReturned | Get-PsSpecHistory -ChangeType Project -Service $testService | ? { $_.PropertyName -eq "Project"} )[0]
AssertEquals "TestProject2" $history.Notes "Should have added history"

## Check that we allow wildcards
$projects = @(Get-PsSpecProject "TestProject*" -Service $testService)
AssertEquals 1 $projects.Count "Should have wildcarded project"

## Check that we can update a project by pipeline
$projects = @(Get-PsSpecProject "TestProject*" -Service $testService)
$projects | Set-PsSpecProject -Description "This is an updated description" -Service $testService
$projects = @(Get-PsSpecProject "TestProject" -Service $testService)
AssertEquals 1 $projects.Count "Should have created project"
$project = $projects[0]

AssertEquals "TestProject" $project.Name
AssertEquals "This is an updated description" $project.Description
AssertEquals "$env:userdomain\$env:username" $project.Owner

$projects = @(Get-PsSpecProject "TestProject" -Service $testService)
AssertEquals 1 $projects.Count "Should have created project"
$project = $projects[0]

## Check that we can update a project name
$project | Set-PsSpecProject -Name "TestProject2" -Service $testService
$projects = @(Get-PsSpecProject "TestProject2" -Service $testService)
AssertEquals 1 $projects.Count "Should have renamed project"
$project = $projects[0]

AssertEquals "TestProject2" $project.Name
AssertEquals "This is an updated description" $project.Description
AssertEquals "$env:userdomain\$env:username" $project.Owner

## Check that old one is gone
$projects = @(Get-PsSpecProject "TestProject" -Service $testService -ErrorAction "SilentlyContinue")
AssertEquals 0 $projects.Count "Should have renamed project (2)"
$error.Clear()

ClearSpecHistory

## Check that we can update both project name and description
$project | Set-PsSpecProject -Name "TestProject" -Description "This is a third updated description" -Service $testService
$projects = @(Get-PsSpecProject "TestProject" -Service $testService)
AssertEquals 1 $projects.Count "Should have renamed project back"
$project = $projects[0]

AssertEquals "TestProject" $project.Name
AssertEquals "This is a third updated description" $project.Description
AssertEquals "$env:userdomain\$env:username" $project.Owner

## Verify that the history was updated
$history = @($project | Get-PsSpecHistory -ChangeType Project -Service $testService | ? { $_.PropertyName -eq "Name"} )
AssertEquals 1 $history.Count "Should have added history"
$history = @($project | Get-PsSpecHistory -ChangeType Project -Service $testService | ? { $_.PropertyName -eq "Description"} )
AssertEquals 1 $history.Count "Should have added history"

## Check for duplicates
[void] (New-PsSpecProject "TestProject" -Service $testService -ErrorAction SilentlyContinue)
AssertEquals 1 $error.Count "Should not be able to create a new project with the same name"
Get-PsSpecProject "TestProject*" -Service $testService | Remove-PsSpecProject -Service $testService -Force
$error.Clear()

## Check for invalid characters in the name
[void] (New-PsSpecProject 'TestProject2!@#$'  -Service $testService -ErrorAction SilentlyContinue)
AssertEquals 1 $error.Count "Should not be able to create a new project with invalid characters"
$projects = @(Get-PsSpecProject '*TestProject2*' -Service $testService)
AssertEquals 0 $projects.Count "Should not have created project with invalid characters"
$error.Clear()

## Add project w/ SQL injection characters
[void] (New-PsSpecProject "TestPro' or 1=1"  -Service $testService -ErrorAction SilentlyContinue)
AssertEquals 1 $error.Count "Should not be able to create a new project with invalid characters (2)"
$error.Clear()

## Check for empty name on creation
$trapped = $false
trap { $SCRIPT:trapped = $true; continue }
[void] (New-PsSpecProject "" -Service $testService)
Assert $trapped "Should not be able to get a new project with invalid characters (3)"
$error.Clear()
trap { throw; break; }

## Check for empty name on get
$trapped = $false
trap { $SCRIPT:trapped = $true; continue }
Get-PsSpecProject "" -Service $testService
Assert $trapped "Should not be able to get a new project with invalid characters (3)"
$error.Clear()
trap { throw; break; }

## Check for too long name
$trapped = $false
trap { $SCRIPT:trapped = $true; continue }
[void] (New-PsSpecProject $('A'*51) -Service $testService -ErrorAction SilentlyContinue)
Assert $trapped "Should not be able to create a new project with too long of a name"
trap { throw; break; }

$projects = @(Get-PsSpecProject "AAAA*" -Service $testService -ErrorAction SilentlyContinue)
AssertEquals 0 $projects.Count "Should not have created project with too long name"
$error.Clear()

## Check that we get an error if you try to remove a project that doesn't exist
Remove-PsSpecProject "ProjectThatDoesNotExist" -Service $testService -Force
AssertEquals 1 $error.Count "Should not be able to remove a project that does not exist."
$error.Clear()

## Check that we do not get an error if you use globbing and try to remove a project that doesn't exist
Get-PsSpecProject "ProjectThatDoesNotExist*" -Service $testService | Remove-PsSpecProject -Service $testService-Force
AssertEquals 0 $error.Count "Should not have generated an error because of globbing."
$error.Clear()

## Check that we can remove a project with -Force, and it takes all cmdlets and parameters
Get-PsSpecProject "TestProject*" -Service $testService | Remove-PsSpecProject -Service $testService -Force

## Add the project
$projectReturned = New-PsSpecProject "TestProject" "This is a description of my project" -Service $testService

## Add the noun
Get-PsSpecNoun "TestNoun*" -Service $testService | Remove-PsSpecNoun -Service $testService -Force
[void] (New-PsSpecNoun TestNoun TestNounDescription TestProject -Service $testService)

## Add the cmdlet
$cmdlet = (New-PsSpecCmdlet -Snapin "FooSnapin" -Verb "Get" -Noun "TestNoun" -Project "TestProject" -ShortDescription "Short Description" `
    -LongDescription "Long Description" -SupportsShouldProcess -Note "These are my notes" -Service $testService)
$cmdlet = Get-PsSpecCmdlet -Project TestProject -Name "Get-TestNoun" -Service $testService
AssertEquals "Get-TestNoun" ($cmdlet.Verb + "-" + $cmdlet.Noun) "Should have created the cmdlet"

## Add a minimal parameter
Add-PsSpecCmdletParameter -ProjectName "TestProject" -CmdletName "Get-TestNoun" -Name "TestParameter" -Type "String" -Service $testService

## Try to clean up the test project
Get-PsSpecProject "TestProject*" -Service $testService | Remove-PsSpecProject -Service $testService -Force
$projects = @(Get-PsSpecProject "TestProject*" -Service $testService)
AssertEquals 0 $projects.Count "Should have removed projects and dependencies."

ClearSpecHistory

## Verify we're at a clean slate
$projects = @(Get-PsSpecProject "TestProject*" -Service $testService)
AssertEquals 0 $projects.Count "Should have removed projects and dependencies."
